/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package me.panpf.sketch.sample.widget.fraction;

import cn.bingoogolapple.refreshlayout.BgaStickinessRefreshViewHolder;
import cn.bingoogolapple.refreshlayout.BgarefreshLayout;
import me.panpf.sketch.Sketch;
import me.panpf.sketch.SketchImageView;
import me.panpf.sketch.datasource.DataSource;
import me.panpf.sketch.request.RequestLevel;
import me.panpf.sketch.sample.*;
import me.panpf.sketch.sample.slice.ImageDetailAbility;
import me.panpf.sketch.sample.slice.NetImageUtils;
import me.panpf.sketch.sample.util.DataTransferStation;
import me.panpf.sketch.sample.util.PxUtil;
import me.panpf.sketch.sample.util.ScrollingPauseLoadManager;
import me.panpf.sketch.sample.widget.SampleImageView;
import me.panpf.sketch.shaper.RoundRectImageShaper;
import me.panpf.sketch.uri.*;
import me.panpf.sketch.util.SketchUtils;
import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.aafwk.ability.fraction.FractionAbility;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.agp.utils.Point;
import ohos.agp.utils.TextTool;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.data.resultset.ResultSet;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.ImageInfo;
import ohos.media.image.common.Size;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import java.io.*;
import java.util.*;

/**
 * PhotosFraction
 */
public class PhotosFraction extends Fraction {

    private static String testFileName = "sample.jpg";
    private MyItemProvider itemProvider;
    private ListContainer mListContainer;
    private BgarefreshLayout mRefreshLayout;
    private DataTransferStation.PageHelper dataTransferHelper;
    private List<String> mAllImages;

    /**
     * getAllImages 获取图片集
     *
     * @param context
     * @return List<String>
     * @throws Exception
     */
    public static List<String> getAllImages(Context context) {
        List<String> imagePath;
        {
            imagePath = new ArrayList<>(Arrays.asList(AssetImage.getAll(context)));
        }

        List<String> dataImages = getDataImage(context);
        try {
            if (dataImages.size() > 0) {
                for (int i1 = dataImages.size() - 1; i1 >= 0; i1--) {
                    imagePath.add(dataImages.get(i1));
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return imagePath;
    }

    private static List<String> getDataImage(Context context) {
        List<String> dataImgs = new ArrayList<>();
        try {
            DataAbilityHelper helper = DataAbilityHelper.creator(context);
            ResultSet resultSet = helper.query(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, null, null);
            if (resultSet == null) {
                return dataImgs;
            }
            List<String[]> urls = new ArrayList<>();
            while (resultSet.goToNextRow()) {
                int mediaId = resultSet.getInt(resultSet.getColumnIndexForName(AVStorage.Audio.Media.ID));
                Uri uri = Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, "" + mediaId);
                String path = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.Images.Media.DATA));
                String mimetype = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.Images.Media.MIME_TYPE));
                String size = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.Images.Media.SIZE));
                String date_modified = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.Images.Media.DATE_MODIFIED));
                orderByTime(urls, uri, date_modified);

            }
            resultSet.close();

            for (String[] url : urls) {
                dataImgs.add(url[1]);
            }
        } catch (DataAbilityRemoteException ex) {
            ex.printStackTrace();
        }
        return dataImgs;
    }

    private static void orderByTime(List<String[]> urls, Uri uri, String date_modified) {
        String[] strings = {date_modified, uri.toString()};
        if (urls.isEmpty()) {
            urls.add(strings);
            return;
        }
        for (int i1 = 0; i1 < urls.size(); i1++) {
            String time = urls.get(i1)[0];
            if (Long.parseLong(date_modified) < Long.parseLong(time)) {
                urls.add(i1, strings);
                return;
            }
        }
        urls.add(strings);
    }

    /**
     * onAppStart 初始化开始
     */
    public static void onAppStart() {
        if (exist(SampleApplication.sSampleApplication, testFileName)) {
            return;
        }
        Context context = SampleApplication.sSampleApplication;
        saveFile(context, ResourceTable.Media_mei_nv, testFileName);
    }

    /**
     * saveFile 保存文件
     *
     * @param context context
     * @param resId resId
     * @param fileName fileName
     * @return boolean
     */
    public static boolean saveFile(Context context, int resId, String fileName) {
        try {
            String path = context.getResourceManager().getMediaPath(resId);
            if (path.isEmpty()) {
                return false;
            }
            RawFileEntry rawFileEntry = context.getResourceManager().getRawFileEntry(path);
            Resource resource = rawFileEntry.openRawFile();
            return saveFile(resource, new File(context.getExternalCacheDir(), fileName));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

    /**
     * saveFile 保存文件
     *
     * @param is is
     * @param toFile toFile
     * @return boolean
     */
    public static boolean saveFile(InputStream is, File toFile) {
        OutputStream os = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            os = new FileOutputStream(toFile);
            // 创建缓冲流
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(os);
            int content;
            while ((content = bis.read()) != -1) {
                // 使用缓冲流写数据
                bos.write(content);
                // 刷新
                bos.flush();
            }
            return true;
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
            if (toFile.exists()) {
                boolean delete = toFile.delete();
                if (delete) {
                }
            }
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return false;
    }

    /**
     * getFile 获取文件
     *
     * @param context context
     * @param fileName fileName
     * @return File File
     */
    public static File getFile(Context context, String fileName) {
        File file = new File(context.getExternalCacheDir(), fileName);
        if (file.exists()) {
            return file;
        }
        return null;
    }

    /**
     * exist 判断文件是否存在
     *
     * @param context context
     * @param fileName fileName
     * @return boolean
     */
    public static boolean exist(Context context, String fileName) {
        File file = getFile(context, fileName);
        return exist(file);
    }

    /**
     * 判断文件是否存在
     *
     * @param file
     * @return boolean
     */
    public static boolean exist(File file) {
        if (file == null) {
            return false;
        }
        return file.exists();
    }


    /**
     * decodeResource加载一个PixelMap
     *
     * @param context 上下文
     * @param id      ResourceTable.Media_icon
     * @return PixelMap PixelMap
     */
    public static PixelMap decodeResource(Context context, int id) {
        try {
            String path = context.getResourceManager().getMediaPath(id);
            if (path.isEmpty()) {
                return null;
            }
            RawFileEntry assetManager = context.getResourceManager().getRawFileEntry(path);
            ImageSource.SourceOptions options = new ImageSource.SourceOptions();
            options.formatHint = "image/png";
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            Resource asset = assetManager.openRawFile();
            ImageSource source = ImageSource.create(asset, options);
            return Optional.ofNullable(source.createPixelmap(decodingOptions)).get();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * displayImage 展示图片
     *
     * @param context         context
     * @param sketchImageView sketchImageView
     * @param uri             uri
     */
    public static void displayImage(Context context, SketchImageView sketchImageView, String uri) {
        sketchImageView.getOptions().setLoadingImage(ResourceTable.Media_image_loading);
        if (TextTool.isNullOrEmpty(uri)) {
            return;
        }
        if (uri.startsWith(AssetUriModel.SCHEME)) {
            Sketch.with(context).displayFromAsset(uri, sketchImageView).commit();
            return;
        }

        Sketch.with(context).display(uri, sketchImageView).commit();
    }

    @Override
    protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
        return scatter.parse(ResourceTable.Layout_photos_fraction, container, false);
    }

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        dataTransferHelper = new DataTransferStation.PageHelper(this);
        dataTransferHelper.onCreate(intent);

        mRefreshLayout = (BgarefreshLayout) getComponent().findComponentById(ResourceTable.Id_bgaRefreshLayout);
        mRefreshLayout.setDelegate(new BgarefreshLayout.BgarefreshLayoutDelegate() {
            @Override
            public void onBgarefreshLayoutBeginRefreshing(BgarefreshLayout bgarefreshLayout) {
                getFractionAbility().getUITaskDispatcher().asyncDispatch(new Runnable() {
                    @Override
                    public void run() {
                        itemProvider.setDataList();
                        itemProvider.notifyDataChanged();
                        mRefreshLayout.endRefreshing();
                    }
                });
            }

            @Override
            public boolean onBgarefreshLayoutBeginLoadingMore(BgarefreshLayout bgarefreshLayout) {
                return false;
            }
        });
        BgaStickinessRefreshViewHolder srfViewHolder = new BgaStickinessRefreshViewHolder(getComponent().getContext(), true);
        mRefreshLayout.setIsShowLoadingMoreView(false);
        mRefreshLayout.setPullDownRefreshEnable(true);
        mRefreshLayout.setRefreshViewHolder(srfViewHolder);


        mListContainer = (ListContainer) getComponent().findComponentById(ResourceTable.Id_listContainer);
        itemProvider = new MyItemProvider();
        mListContainer.addScrolledListener(new ScrollingPauseLoadManager(getFractionAbility(), itemProvider));
        mListContainer.setItemProvider(itemProvider);
        mListContainer.setLongClickable(false);
        itemProvider.notifyDataChanged();

        mRefreshLayout.beginRefreshing();
    }

    private class MyItemProvider extends BaseItemProvider {
        private final List<String[]> dataList = new ArrayList<>();

        public MyItemProvider() {
            setDataList();
        }

        void setDataList() {
            dataList.clear();

            try {
                mAllImages = getAllImages(getFractionAbility());
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            if (mAllImages == null) {
                return;
            }
            if (mAllImages.isEmpty()) {
                return;
            }

            for (int i1 = 0; i1 < mAllImages.size(); i1++) {
                if (i1 % 3 == 0) {
                    String[] image = new String[3];
                    image[0] = mAllImages.get(i1);
                    dataList.add(image);
                } else {
                    String[] image = dataList.get(i1 / 3);
                    image[i1 % 3] = mAllImages.get(i1);
                }
            }
        }

        @Override
        public int getCount() {
            return dataList.size();
        }

        @Override
        public Object getItem(int i) {
            return dataList.get(i);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) {
            final Component cpt;
            MyViewHolder viewHolder;
            if (convertComponent == null) {
                Context context = PhotosFraction.this.getFractionAbility().getContext();
                cpt = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_photo, componentContainer, false);
                viewHolder = new MyViewHolder();
                viewHolder.image1 = (SampleImageView) cpt.findComponentById(ResourceTable.Id_image1);
                viewHolder.image2 = (SampleImageView) cpt.findComponentById(ResourceTable.Id_image2);
                viewHolder.image3 = (SampleImageView) cpt.findComponentById(ResourceTable.Id_image3);
                viewHolder.image1.setPage(SampleImageView.Page.PHOTO_LIST);
                viewHolder.image2.setPage(SampleImageView.Page.PHOTO_LIST);
                viewHolder.image3.setPage(SampleImageView.Page.PHOTO_LIST);

                Optional<Display> display = DisplayManager.getInstance().getDefaultDisplay(context);
                Point pt = new Point();
                display.get().getSize(pt);

                int width = (int) ((pt.getPointX() - (double) (PxUtil.vp2px((float) (4 * 4d)))) / 3d);
                viewHolder.image1.setWidth(width);
                viewHolder.image2.setWidth(width);
                viewHolder.image3.setWidth(width);
                viewHolder.image1.setHeight(width);
                viewHolder.image2.setHeight(width);
                viewHolder.image3.setHeight(width);

                cpt.setTag(viewHolder);
            } else {
                cpt = convertComponent;
                viewHolder = (MyViewHolder) cpt.getTag();
            }

            setImage(position, viewHolder);

            return cpt;
        }

        private void setImage(int position, MyViewHolder viewHolder) {
            for (SampleImageView sampleImageView : new SampleImageView[]{viewHolder.image1, viewHolder.image2, viewHolder.image3}) {
                sampleImageView.setPage(SampleImageView.Page.PHOTO_LIST);
                if (AppConfig.getBoolean(getFractionAbility(), AppConfig.Key.SHOW_ROUND_RECT_IN_PHOTO_LIST)) {
                    sampleImageView.getOptions().setLoadingImage(ResourceTable.Media_image_loading)
                            .setErrorImage(ResourceTable.Media_image_error)
                            .setPauseDownloadImage(ResourceTable.Media_image_pause_download)
                            .setShaper(new RoundRectImageShaper(SketchUtils.dp2px(getFractionAbility(), 6)));
                } else {
                    sampleImageView.getOptions().setLoadingImage(ResourceTable.Media_image_loading)
                            .setErrorImage(ResourceTable.Media_image_error)
                            .setPauseDownloadImage(ResourceTable.Media_image_pause_download);

                }
            }

            viewHolder.image1.setVisibility(Component.INVISIBLE);
            viewHolder.image2.setVisibility(Component.INVISIBLE);
            viewHolder.image3.setVisibility(Component.INVISIBLE);

            String[] strings = dataList.get(position);
            getFractionAbility().createParallelTaskDispatcher("photos", TaskPriority.HIGH).asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    for (String string : strings) {
                        setIsNetImage(string);
                    }
                }
            });

            if (strings[0] == null) {
                return;
            }
            viewHolder.image1.setVisibility(Component.VISIBLE);
            viewHolder.image1.setClickedListener(component -> goToDetail(component, position, 0));
            displayImage(getFractionAbility().getContext(), viewHolder.image1, strings[0]);
            if (strings[1] == null) {
                return;
            }
            viewHolder.image2.setVisibility(Component.VISIBLE);
            viewHolder.image2.setClickedListener(component -> goToDetail(component, position, 1));
            displayImage(getFractionAbility().getContext(), viewHolder.image2, strings[1]);

            if (strings[2] == null) {
                return;
            }
            viewHolder.image3.setVisibility(Component.VISIBLE);
            displayImage(getFractionAbility().getContext(), viewHolder.image3, strings[2]);
            viewHolder.image3.setClickedListener(component -> goToDetail(component, position, 2));
        }

        private void goToDetail(Component component, int position, int index) {
            String finalOptionsKey = ((SketchImageView) component).getOptionsKey();
            // 含有这些信息时，说明这张图片不仅仅是缩小，而是会被改变，因此不能用作loading图了
            if (finalOptionsKey.contains("Resize")
                    || finalOptionsKey.contains("ImageProcessor")
                    || finalOptionsKey.contains("thumbnailMode")) {
                finalOptionsKey = null;
            }

            if (mAllImages.size() > 0) {
                String urlList = dataTransferHelper.put("urlList", mAllImages);
                ImageDetailAbility.launch(getFractionAbility(),
                        urlList,
                        finalOptionsKey, position * 3 + index);
            }
        }

        private void setIsNetImage(String url) {
            if (TextTool.isNullOrEmpty(url)) {
                return;
            }
            if (!url.startsWith("http")) {
                return;
            }

            FractionAbility context = getFractionAbility();
            UriModelManager manager = Sketch.with(context).getConfiguration().getUriModelManager();

            ImageInfo imageInfo;
            try {
                DataSource dataSource = manager.match(url).getDataSource(context, url, null);
                ImageSource imageSource = ImageSource.create(dataSource.getInputStream(), null);
                imageInfo = imageSource.getImageInfo();
            } catch (Exception ignored) {
                imageInfo = new ImageInfo();
                imageInfo.size = new Size(100, 100);
            }

            ImageDetailAbility.MImageInfo info = new ImageDetailAbility.MImageInfo(imageInfo, SketchUtils.isGifImage(url), url, null);
            NetImageUtils.getInstance().datas.put(url, info);
        }

        class MyViewHolder {
            SampleImageView image1;
            SampleImageView image2;
            SampleImageView image3;
        }
    }

}
